package system;

import java.sql.Date;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import bean.UserBean;
import dao.DAO;
import dao.DBFacade;
import dao.UserDAO;
import exceptions.InvalidAttributeException;
import exceptions.InvalidAttributeException2;
import exceptions.InvalidAudioException;
import exceptions.InvalidBlogException;
import exceptions.InvalidDataException;
import exceptions.InvalidIdException;
import exceptions.InvalidIndexException;
import exceptions.InvalidLoginException;
import exceptions.InvalidLoginOrPasswordException;
import exceptions.InvalidPostException;
import exceptions.InvalidSessionException;
import exceptions.NonexistentUserException;
import exceptions.TitleUnspecifiedException;
import exceptions.UserAlreadyLoggedInException;
import exceptions.WrongIndexException;

/**
 * Class responsible for all the operations
 * @author Anne Lorayne, Laura Dutra, Francisco Otavio
 *
 */
public class BlogSystem {
	
	private List<User> allUsers;
	private Map<String, User> loggedUsers;
	private static BlogSystem instance;
	private static DAO<UserBean> userDAO = UserDAO.getInstance();
	private DBFacade db = DBFacade.getInstance(); // TODO remove this guy

	/**
	 * Private constructor - Singleton.
	 */
	private BlogSystem() {
		loggedUsers = new HashMap<String, User>();
		allUsers = getAllUsers();
		
		
	}
	
		/**
	 * Singleton.
	 * 
	 * @return A BlogSystem Instance
	 */
	public static synchronized BlogSystem getInstance() {
		if (instance == null)
			instance = new BlogSystem();
		return instance;

	}
	

	/**
	 * Capturing today's date and returns the format dd/MM/yyyy
	 * @return today's date
	 */
	public String todaysDate() {
		Date data = new Date(System.currentTimeMillis());
		SimpleDateFormat formatarDate = new SimpleDateFormat("dd/MM/yyyy");
		return formatarDate.format(data);
	}

	/**
	 * Allows one user to access the system
	 * 
	 * @param login
	 *            - User's login
	 * @param password
	 *            - User's password
	 * @return SessionID - Its must be unique.
	 * @throws Throws
	 *             exception if given user or password does not match. Or if
	 *             given users is already logged in.
	 */
	public String login(String login, String password) throws Exception {

		Iterator<User> users = loggedUsers.values().iterator();
		while (users.hasNext()) {
			User user = users.next();
			if (user.getLogin().equals(login)) {
				throw new UserAlreadyLoggedInException();
			}
		}
		User user;
		String sessionID;
		for(Iterator<User> it = allUsers.iterator(); it.hasNext();){
			
			user = it.next();
			if(user.getLogin().equals(login)){
				if(user.getPassword().equals(password)){
					do {
						sessionID = Long.toString(System.currentTimeMillis());
					} while (loggedUsers.containsKey(sessionID));
					loggedUsers.put(sessionID, user);
					return sessionID;
				}else {
					throw new InvalidLoginOrPasswordException();
				}
					
			}
		}
		throw new InvalidLoginOrPasswordException();
		
		

//		Iterator<UserBean> usersBean = userDAO.list().iterator();
//
//		String sessionID;
//
//		while (usersBean.hasNext()) {
//			UserBean user = usersBean.next();
//
//			if (user.getLogin().equals(login)) {
//				if (user.getPassword().equals(password)) {
//					do {
//						sessionID = Long.toString(System.currentTimeMillis());
//					} while (loggedUsers.containsKey(sessionID));
//					User u = new User(user);
//					loggedUsers.put(sessionID, u);
//					return sessionID;
//				} else
//					throw new Exception("Login ou senha inválido");
//			} else
//				;
//		}
//		throw new Exception("Login ou senha inválido");
	}

	/**
	 * Performs a logout of a given SessionID
	 * 
	 * @param sessionID
	 *            - The session which wants to be finished
	 * @return true if the logout was successful, false otherwise.
	 * @throws Exception
	 *             - Throws exception if given sessionID is not a valid one.
	 */
	public boolean logout(String sessionID) throws Exception {
		if (!(loggedUsers.containsKey(sessionID)))
			throw new InvalidSessionException();
		loggedUsers.remove(sessionID);
		return true;
	}
	
	//User Operations

	/**
	 * 
	 * Create a new user.
	 * 
	 * @param login
	 *            - User's login
	 * @param password
	 *            - Users's password
	 * @param name
	 *            - User's name
	 * @param email
	 *            - Users's email
	 * @param gender
	 *            - Users's gender
	 * @param dateOfBirth
	 *            - User's dateOfBirth
	 * @param address
	 *            - User's address
	 * @param interests
	 *            - User's interests
	 * @param whoIAm
	 *            - User's whoIAm
	 * @param movies
	 *            - User's movies preferences
	 * @param musics
	 *            - User's musics preferences
	 * @param books
	 *            - User's books preferences
	 * @return TODO add returns comments
	 * @throws Exception
	 *             TODO add excp comments
	 */
	// TODO CHECAR STRING->CALENDAR
	// TODO CHECAR ENUM(GENDER)->STRING
	public boolean createUser(String login, String password, String name,
			String email, String gender, String dateOfBirth, String address,
			String interests, String whoIAm, String movies, String musics,
			String books) throws Exception {
		allUsers.add(new User(login, password, name, email, gender, dateOfBirth, address,
				interests, whoIAm, movies, musics, books));
		return true;
	}

	/**
	 * Changes a profile on system based on a given SessionID
	 * 
	 * @param sessionID
	 * @param attribute
	 * @param newValue
	 * @throws Exception
	 */
	public void changeProfileInformation(String sessionID, String attribute,
			String newValue) throws Exception {
		if (!(loggedUsers.containsKey(sessionID)))
			throw new InvalidSessionException();
		User user = loggedUsers.get(sessionID);
		user.updateUser(attribute, newValue);
	}
	
	/**
	 * Retrieves a users attribute value
	 * 
	 * @param login
	 *            - User's login
	 * @param attribute
	 *            - Attribute which you wants to know value
	 * @throws Exception
	 *             - Throwns exceptions if given att is invalid
	 */
	public String getInformationProfileBySessionId(String sessionID,
			String attribute) throws Exception {
		return User.getInformationProfile(
				loggedUsers.get(sessionID).getLogin(), attribute);
	}
	
	/**
	 * Retrieves a users attribute value
	 * 
	 * @param login
	 *            - User's login
	 * @param attribute
	 *            - Attribute which you wants to know value
	 * @throws Exception
	 *             - Throwns exceptions if given att is invalid
	 */
	public String getInformationProfile(String login, String attribute)
	throws Exception {
		return User.getInformationProfile(login, attribute);
	}


	
	/**
	 * Delete a profile
	 * @param sessionId
	 * @throws Exception
	 */
	public void deleteProfile(String sessionId) throws Exception {
		if(loggedUsers.containsKey(sessionId)){
			allUsers.remove(loggedUsers.get(sessionId));
			loggedUsers.get(sessionId).delete();
			loggedUsers.remove(sessionId);
		} else {
			throw new InvalidSessionException();
		}
	}
	
	/**
	 * Check if a given user (login) is logged on system
	 * 
	 * @param login
	 * @return true if the user (login) is logged, false otherwise
	 * @throws Exception
	 */
	public boolean isUserLogged(String login) throws Exception {
		Iterator<UserBean> usersBean = userDAO.list().iterator();

		while (usersBean.hasNext()) {
			UserBean userBean = usersBean.next();
			if (userBean.getLogin().equals(login)) {
				Iterator<User> users = loggedUsers.values().iterator();
				while (users.hasNext()) {
					User user = users.next();
					if (user.getLogin().equals(login)) {
						return true;
					}
				}
				return false;
			} else
				;
		}

		throw new NonexistentUserException();

	}



	//Blog Operations
	/**
	 * Creates a new blog on system
	 * 
	 * @param sessionID
	 *            - Must be a valid ID to create a blog
	 * @param title
	 *            - Blog's title
	 * @param description
	 *            - Blog's description
	 * @return blogID
	 * @throws Exception
	 *             If not given a valid sessionID throws exception
	 */
	public String createBlog(String sessionID, String title, String description)
	throws Exception {
		if (loggedUsers.containsKey(sessionID)) {
			User user = loggedUsers.get(sessionID);
			return user.addBlog(title, description);
		}
		throw new InvalidSessionException();
		
	}
	
	/**
	 * Changes a blog on system based on a given SessionID
	 * 
	 * @param sessionID
	 * @param blogID
	 * @param attribute
	 * @param newValue
	 * @throws Exception
	 */
	public void changeBlogInformation(String sessionId, String blogId,
			String attribute, String newValue) throws Exception {
		if (attribute == null || attribute.equals(""))
			throw new InvalidAttributeException2();
		if (!(loggedUsers.containsKey(sessionId)))
			throw new InvalidSessionException();
		if (attribute.equals("titulo")
				&& (newValue == null || newValue.equals("")))
			throw new TitleUnspecifiedException();
		
		String id;
		for(Iterator<String> it = loggedUsers.keySet().iterator(); it.hasNext();){
			id = it.next();
			if(loggedUsers.get(id).hasBlog(blogId)){
				if(!id.equals(sessionId))
					throw new InvalidSessionException();
				loggedUsers.get(id).updateBlog(blogId, attribute, newValue);
				return;
			}
		}
		throw new InvalidBlogException();
	}


	
	/**
	 * Retrieves a blog attribute value
	 * 
	 * @param blogID
	 * @param attribute
	 *            - Attribute which you wants to know value
	 * @return attribute value
	 * @throws Exception
	 *             - Throwns exceptions if given att is invalid
	 */
	public String getInformationBlog(String blogID, String attribute)
	throws Exception {
		return Blog.getInformationBlog(blogID, attribute);
	}
	
//	public void createSubBlogs() {
		//TODO
//	}

//	public void notifY() {
		//TODO
//	}

	//Post Operations
	/**
	 * Creare a new post
	 * @param sessionId
	 * @param blogId
	 * @param title
	 * @param text
	 * @return postId
	 * @throws Exception
	 */
	public String createPost(String sessionId, String blogId, String title,
			String text) throws Exception {
				
		if(!loggedUsers.containsKey(sessionId))
			throw new InvalidSessionException();
		if(blogId == null)
			throw new InvalidBlogException();
		
		for (String session : loggedUsers.keySet()) 
			if(loggedUsers.get(session).hasBlog(blogId) && !session.equals(sessionId))
					throw new InvalidSessionException();
					
		
		return loggedUsers.get(sessionId).addPost(blogId, title, text, todaysDate());
	
	}
	
	/**
	 * Retrieves a post attribute value
	 * 
	 * @param postID
	 * @param attribute
	 *            - Attribute which you wants to know value
	 * @return attribute value
	 * @throws Exception
	 *             - Throwns exceptions if given att is invalid
	 */
	public String getPostInformation(String postId, String attribute)
		throws Exception {
		
		User user;
		for(Iterator<User> it = allUsers.iterator(); it.hasNext();){
			user = it.next();
			if(user.hasPost(postId))
				return user.getPostInformation(postId, attribute);
		}
		return null; 
	}
	
//	public boolean editPost(String title, String content, String image,
//			String video, String sound) {
//		return false;
//	}
	
	/**
	 * Delete a post
	 * @param sessionId
	 * 			- Identifier of the session to validate the User logon
	 * @param postId
	 * 			- Identifier of the post will be deleted 
	 * @throws Exception
	 */
	public void deletePost(String sessionId, String postId) throws Exception {
		if(!loggedUsers.containsKey(sessionId))
			throw new InvalidSessionException();
		loggedUsers.get(sessionId).deletePost(postId);
		
	}


	//Media operations
	/**
	 * Attaches a sound
	 * @param sessionID
	 * 			- Identifier of the session to validate the User logon
	 * @param postID
	 * 			- Identifier of the post that will be inserted audio
	 * @param description
	 * 			- Sound's description
	 * @param data
	 * 			- Data's sound
	 * @return soundId
	 *          - Identifier of the sound
	 * @throws Exception
	 */
	public String attachSound(String sessionID, String postID,
			String description, String data) throws Exception {
		if(data == null || data.equals(""))
			throw new InvalidDataException();
		if(!loggedUsers.containsKey(sessionID))
			throw new InvalidSessionException();
		
		User user = loggedUsers.get(sessionID);
		Iterator<Blog> blogList = user.getInstanceBlogList().iterator();
		while (blogList.hasNext()) {
			Blog blog = blogList.next();
			if(blog.hasPost(postID)){
				return blog.addSoundToPost(postID, data, description);
			}
		}
		return null;
	}

	/**
	 * Attaches a movie
	 * @param sessionID
	 * 			- Identifier of the session to validate the User logon
	 * @param postID
	 * 			- Identifier of the post that will be inserted sound
	 * @param description
	 * 			- Movie's description
	 * @param data
	 * 			- Data's movie
	 * @return moviedId
	 *          - Identifier of the movie
	 * @throws Exception
	 */
	public String attachMovie(String sessionID, String postID,
			String description, String data) throws Exception {
		if(data == null || data.equals(""))
			throw new InvalidDataException();
		if(!loggedUsers.containsKey(sessionID))
			throw new InvalidSessionException();

		User user = loggedUsers.get(sessionID);
		Iterator<Blog> blogList = user.getInstanceBlogList().iterator();
		while (blogList.hasNext()) {
			Blog blog = blogList.next();
			if(blog.hasPost(postID)){
				return blog.addMovieToPost(postID, data, description);
				
			}
		}

		return null;
	}

	/**
	 * Attaches a picture
	 * @param sessionID
	 * 			- Identifier of the session to validate the User logon
	 * @param postID
	 * 			- Identifier of the post that will be inserted picture
	 * @param description
	 * 			- Picture's description
	 * @param data
	 * 			- Data's picture
	 * @return pictureId
	 *          - Identifier of the picture
	 * @throws Exception
	 */
	public String attachPicture(String sessionID, String postID,
			String description, String data) throws Exception {
		if(data == null || data.equals(""))
			throw new InvalidDataException();
		if(!loggedUsers.containsKey(sessionID))
			throw new InvalidSessionException();

		User user = loggedUsers.get(sessionID);
		Iterator<Blog> blogList = user.getInstanceBlogList().iterator();
		while (blogList.hasNext()) {
			Blog blog = blogList.next();
			if(blog.hasPost(postID)){
				return blog.addPictureToPost(postID, data, description);
				
			}
		}
		return null;
	}

	/**
	 * Returns the number of sounds from post
	 * @param postId
	 * 			- Identifier of the post sounds to be counted
	 * @return number of sounds
	 * @throws Exception
	 */
	public long getNumberOfSoundsOfPost(String postId) throws Exception {
		for(Iterator<User> it = allUsers.iterator(); it.hasNext();){
			User user = it.next();
			if(user.hasPost(postId))
				return user.getNumberOfSoundsOfPost(postId);
			
		}
		throw new InvalidPostException();
	}

	/**
	 * Returns the number of pictures from post
	 * @param postId
	 * 			- Identifier of the post pictures to be counted
	 * @return number of pictures
	 * @throws Exception
	 */
	public long getNumberOfPicturesOfPost(String postId) throws Exception {
		for(Iterator<User> it = allUsers.iterator(); it.hasNext();){
			User user = it.next();
			if(user.hasPost(postId))
				return user.getNumberOfPicturesOfPost(postId);
		}
		throw new InvalidPostException();
	}
	
	/**
	 * Returns the number of movies from post
	 * @param postId
	 * 			- Identifier of the post movies to be counted
	 * @return number of movies
	 * @throws Exception
	 */
	public long getNumberOfMoviesOfPost(String postId) throws Exception {
		for(Iterator<User> it = allUsers.iterator(); it.hasNext();){
			User user = it.next();
			if(user.hasPost(postId))
				return user.getNumberOfMoviesOfPost(postId);
		}
		throw new InvalidPostException();
		
	}
	
	/**
	 * Capturing the sound of the post with the index passed as parameter
	 * @param postId
	 * 			- Identifier of the post which will capture the sound
	 * @param index
	 * 			- Sound's index
	 * @return soundId
	 * @throws Exception
	 */
	public String getSound(String postId, long index) throws Exception {
		if(index < 0 || index > getNumberOfSoundsOfPost(postId))
			throw new InvalidIndexException();
		
		for(Iterator<User> it = allUsers.iterator(); it.hasNext();){
			User user = it.next();
			if(user.hasPost(postId))
				return user.getSound(postId, index);
		}
		throw new InvalidPostException();
	}
	
	/**
	 * Capturing the movie of the post with the index passed as parameter
	 * @param postId
	 * 			- Identifier of the post which will capture the movie
	 * @param index
	 * 			- Movie's index
	 * @return movieId
	 * @throws Exception
	 */
	public String getMovie(String postId, long index) throws Exception {
		if(index < 0 || index > getNumberOfMoviesOfPost(postId))
			throw new InvalidIndexException();
		for(Iterator<User> it = allUsers.iterator(); it.hasNext();){
			User user = it.next();
			if(user.hasPost(postId))
				return user.getMovie(postId, index);
		}
		throw new InvalidPostException();
	}
	
	/**
	 * Capturing the picture of the post with the index passed as parameter
	 * @param postId
	 * 			- Identifier of the post which will capture the picture
	 * @param index
	 * 			- Picture's index
	 * @return pictureId
	 * @throws Exception
	 */
	public String getPicture(String postId, long index) throws Exception {
		if(index < 0 || index >= getNumberOfPicturesOfPost(postId))
			throw new WrongIndexException();
		for(Iterator<User> it = allUsers.iterator(); it.hasNext();){
			User user = it.next();
			if(user.hasPost(postId))
				return user.getPicture(postId, index);
		}
		throw new InvalidPostException();
	}

	
	/**
	 * Returns data of sound
	 * @param soundId
	 * @return data of sound
	 * @throws Exception 
	 */
	public String getMediaData(String mediaId) throws Exception{
		for(Iterator<User> it = allUsers.iterator(); it.hasNext();){
			User user = it.next();
			if(user.hasMedia(mediaId))
				return user.getMediaData(mediaId);
		}
		throw new InvalidAudioException();
	}
	
	/**
	 * Returns description of sound
	 * @param soundId
	 * @return description of sound
	 * @throws Exception 
	 */
	public String getMediaDescription(String mediaId) throws Exception{
		for(Iterator<User> it = allUsers.iterator(); it.hasNext();){
			User user = it.next();
			if(user.hasMedia(mediaId))
				return user.getMediaDescription(mediaId);
		}
		throw new InvalidIdException();
	}

	//Comment Operations
	/**
	 * Add a comment
	 * @param sessionId
	 * 			- Identifier of the session to validate the User logon
	 * @param postId
	 * 			- identifier of the post which is inserted into the comment
	 * @param comment
	 * 			- Text's comment
	 * @return
	 * @throws Exception
	 */
	public String addComment(String sessionId, String postId, String comment) throws Exception {
		if (loggedUsers.containsKey(sessionId)) {
			User user;
			for (Iterator<User> users = allUsers.iterator(); users.hasNext();) {
				user = users.next();
				if(user.hasPost(postId)){
					return user.addComment(postId, comment, loggedUsers.get(sessionId).getLogin());
				}
				
			}
		}
		throw new InvalidSessionException();
	}

//	public void addCommentToComment() {
		//TODO
//	}
	

	//Search Operations
//	public void search() {
		//TODO
//	}

	//Private methods
	
	/**
	 * Captures all users
	 * @return user's list
	 */
	private List<User> getAllUsers(){
		List<User> users = new ArrayList<User>();
		List<UserBean> beans = userDAO.list();
		for(Iterator<UserBean> it = beans.iterator(); it.hasNext();){
			users.add(new User(it.next()));
		}
		return users;
	}

	//US7
	/**
	 * Returns the number of blogs login passed as parameter
	 * @param login
	 * @return number of blogs
	 */
	public int getNumberOfBlogsByLogin(String login) {
		for(Iterator<User> it = allUsers.iterator(); it.hasNext();){
			User user = it.next();
			if(user.getLogin().equals(login))
				return user.getNumberOfBlogs();
		}
		return 0; //throw new Exception("Login inválido");
	}
		
	
	/**
	 * Returns the number if blogs sessionId passed as parameter
	 * @param sessionId
	 * @return number of blogs
	 */
	public int getNumberOfBlogsBySessionId(String sessionId) {
		if(loggedUsers.containsKey(sessionId))
			return getNumberOfBlogsByLogin(loggedUsers.get(sessionId).getLogin());
		
		return 0; //throw new Exception("Sessao inválida");
	}

	/**
	 * Returns the identifier of the blog of the session passed as parameter to index the past too.
	 * @param sessionId
	 * @param index
	 * @return blogId
	 * @throws Exception
	 */
	public String getBlogBySessionId(String sessionId, int index) throws Exception {
		if(loggedUsers.containsKey(sessionId)){
			return getBlogByLogin(loggedUsers.get(sessionId).getLogin(), index);
		}
		throw new InvalidSessionException();
	}

	/**
	 * Returns the identifier of the blog of the login passed as parameter to index the past too.
	 * @param login
	 * @param index
	 * @return blogId
	 * @throws Exception
	 */
	public String getBlogByLogin(String login, int index) throws Exception {
		for(Iterator<User> it = allUsers.iterator(); it.hasNext();){
			User user = it.next();
			if(user.getLogin().equals(login)){
				return user.getBlogAtIndex(index);
			}
		}
	    throw new InvalidLoginException();
	}

	/**
	 * Returns the number of blog posts
	 * @param blogId
	 * @return number of posts
	 * @throws Exception
	 */
	public int getNumberOfPosts(String blogId) throws Exception{
		for(Iterator<User> it = allUsers.iterator(); it.hasNext();){
			User user = it.next();
			if(user.hasBlog(blogId))
				return user.getNumberOfPostsByBlog(blogId);
		}
		throw new InvalidBlogException();
	}

	/**
	 * Capturing the post with the index passed as parameter
	 * @param blogId
	 * 			- Identifier of the blog which will capture the post
	 * @param index
	 * 			- Post's index
	 * @return postId
	 */
	public String getPost(String blogId, int index) {
		for(Iterator<User> it = allUsers.iterator(); it.hasNext();){
			User user = it.next();
			if(user.hasBlog(blogId)){
				return user.getPostAtIndex(blogId, index);
			}
		}
		return null; //throw new Exception("Blog inválido");
	}

	/**
	 * Modifies the information of the post passed as parameter
	 * @param sessionId
	 * 			- Identifier of the session to validate the User logon
	 * @param postId
	 * 			- Identifier of the post modification
	 * @param attribute
	 * 			- Attribute to be modified
	 * @param value
	 * 			- Value that will be inserted
	 * @throws Exception
	 */
	public void changePostInformation(String sessionId, String postId,
			String attribute, String value) throws Exception {
		
		if(!loggedUsers.containsKey(sessionId))
			throw new InvalidSessionException();
		if(postId == null)
			throw new InvalidPostException();
		if(attribute == null)
			throw new InvalidAttributeException2();
		
		for(Iterator<User> it = allUsers.iterator(); it.hasNext();){
			User user = it.next();
			if(user.hasPost(postId)){
				user.changePostInformation(postId, attribute, value);
					return;
			}
		}
		throw new InvalidPostException();
	}

	/**
	 * Delete a movie
	 * @param sessionId
	 * 			- Identifier of the session to validate the User logon
	 * @param movieId
	 * 			- Identifier of the movie will be deleted
	 */
	public void deleteMovie(String sessionId, String movieId) {
		if(loggedUsers.containsKey(sessionId))
			if(loggedUsers.get(sessionId).hasMedia(movieId))
				loggedUsers.get(sessionId).deleteMovie(movieId);
		//throws new Exception("Sessao invalida");
	}
	
	/**
	 * Delete a sound
	 * @param sessionId
	 * 			- Identifier of the session to validate the User logon
	 * @param soundId
	 * 			- Identifier of the sound will be deleted
	 */
	public void deleteSound(String sessionId, String soundId) {
		if(loggedUsers.containsKey(sessionId))
			if(loggedUsers.get(sessionId).hasMedia(soundId))
				loggedUsers.get(sessionId).deleteSound(soundId);
		//throws new Exception("Sessao invalida")
		
	}

	/**
	 * Delete a picture
	 * @param sessionId
	 * 			- Identifier of the session to validate the User logon
	 * @param pictureId
	 * 			- Identifier of the picture will be deleted
	 */
	public void deletePicture(String sessionId, String pictureId) {
		if(loggedUsers.containsKey(sessionId))
			if(loggedUsers.get(sessionId).hasMedia(pictureId))
				loggedUsers.get(sessionId).deletePicture(pictureId);
		//throws new Exception("Sessao invalida")
	}

	/**
	 * Returns the number of comments of post
	 * @param postId
	 * 			- Identifier of the post which will capture the number of comments
	 * @return number of posts
	 * @throws Exception
	 */
	public long getNumberOfComments(String postId) throws Exception {
		
		if(postId == null || postId.trim().equals(""))
			throw new InvalidPostException();
		
		for(Iterator<User> it = allUsers.iterator(); it.hasNext();){
			User user = it.next();
			if(user.hasPost(postId))
				return user.getNumberOfComments(postId);
		}
		return 0; 
	}

	
	/**
	 * Capturing the comment with the index passed as parameter
	 * @param postId
	 * 			- Identifier of the post which will capture the comment
	 * @param index
	 * 			- comment's index
	 * @return commentId
	 */
	public String getComment(String postId, int index) throws Exception {
		if(postId == null || postId.equals(""))
			throw new InvalidPostException();
		for(Iterator<User> it = allUsers.iterator(); it.hasNext();){
			User user = it.next();
			if(user.hasPost(postId))
				return user.getComment(postId, index);
		}
		return null;
	}
	
	/**
	 * Retrieves the comment's text passed as parameter
	 * @param commentId
	 * 			- identifier of the comment that the text will be recovered
	 * @return comment's text
	 * @throws Exception
	 */
	public String getCommentText(String commentId) throws Exception {
		if(commentId == null || commentId.equals(""))
			throw new InvalidPostException();
		for(Iterator<User> it = allUsers.iterator(); it.hasNext();){
			User user = it.next();
			if(user.hasComment(commentId))
				return user.getCommentText(commentId);
		}
		return null;
	}

	/**
	 * Retrieves the comment's author passed as parameter
	 * @param commentId
	 * 			- identifier of the comment that the author will be recovered
	 * @return comment's author
	 * @throws Exception
	 */
	public String getCommentAuthor(String commentId) throws Exception {
		if(commentId == null || commentId.equals(""))
			throw new InvalidPostException();
		for(Iterator<User> it = allUsers.iterator(); it.hasNext();){
			User user = it.next();
			if(user.hasComment(commentId))
				return user.getCommentAuthor(commentId);
		}
		return null;
	}


	/**
	 * Delete a blog
	 * @param sessionId
	 * 			- Identifier of the session to validate the User logon
	 * @param blogId
	 * 			- Identifier of the blog will be deleted
	 * @throws Exception
	 */
	public void deleteBlog(String sessionId, String blogId) throws Exception{
		if(loggedUsers.containsKey(sessionId))
			if(loggedUsers.get(sessionId).hasBlog(blogId))
				loggedUsers.get(sessionId).deleteBlog(blogId);
	}
	
	//US12

	/**
	 * Returns a list of profile by name
	 * @param match
	 * @return list of profile
	 * @throws Exception
	 */
	public List<String> findProfileByName(String match) throws Exception{
		List<String> users = new ArrayList<String>();
		User user;
		for (Iterator<User> it = allUsers.iterator(); it.hasNext();) {
			user = it.next();
			if(getInformationProfile(user.getLogin(), "nome_exibicao").toUpperCase().contains(match.toUpperCase())){
				users.add(user.getLogin());
			}
			
		}
		Collections.sort(users);
		return users;
	}
	
	
	/**
	 * Returns the number of comments of login and blogId
	 * @param login
	 * @param blogId
	 * @return number of comments
	 */
	public String getNumberOfComments(String login, String blogId) {
		User user;
		
		for (Iterator<User> it = allUsers.iterator(); it.hasNext();) {
			user = it.next();
			if(user.hasBlog(blogId)){
				return String.valueOf(user.getNumberOfCommentsByLogin(login));
			}
			
		}
		return "0";
	}

	/**
	 * Returns a list of profile by interests
	 * @param match
	 * @return list
	 * @throws Exception
	 */
	public List<String> findProfileByInterests(String match) throws Exception {
		
		List<String> users = new ArrayList<String>();
		User user;
		for (Iterator<User> it = allUsers.iterator(); it.hasNext();) {
			user = it.next();
			if(getInformationProfile(user.getLogin(), "interesses").toUpperCase().contains(match.toUpperCase())){
				users.add(user.getLogin());
			}
			
		}
		Collections.sort(users);
		return users;
	}

	/**
	 * Returns a list of blog by name passed as parameter
	 * @param match
	 * @return list
	 * @throws Exception
	 */
	public List<String> findBlogByName(String match) throws Exception {
		List<String> blogs = new ArrayList<String>();
		User user;
		for (Iterator<User> it = allUsers.iterator(); it.hasNext();) {
			user = it.next();
			blogs.addAll(user.findBlogByName(match));
						
		}		
		return blogs;
	}

	/**
	 * Returns a list of profile by gender
	 * @param match
	 * @return list
	 * @throws Exception
	 */
	public List<String> findProfileByGender(String match) throws Exception {
		List<String> users = new ArrayList<String>();

		if(match.equals("Não informado")){
			for (Iterator<User> it = allUsers.iterator(); it.hasNext();) {
				users.add(it.next().getLogin());
			}
			Collections.sort(users);
			return users;
		}

		User user;
		for (Iterator<User> it = allUsers.iterator(); it.hasNext();) {
			user = it.next();
			if(getInformationProfile(user.getLogin(), "sexo").toUpperCase().equals(match.toUpperCase())){
				users.add(user.getLogin());
			}
			
		}
		
		Collections.sort(users);
		return users;
	}
	
	//US13

	/**
	 * Returns a number of announcements by sessionId passed as parameter
	 * @param sessionId
	 * @return number of announcements
	 * @throws Exception
	 */
	public int getNumberOfAnnouncements(String sessionId) throws Exception {
		if(!loggedUsers.containsKey(sessionId))
			throw new InvalidSessionException();
		return loggedUsers.get(sessionId).getNumberOfAnnouncements();
	}

	/**
	 * Add a post announcement
	 * @param sessionId
	 * @param blogId
	 * @throws Exception
	 */
	public void addPostAnnouncements(String sessionId, String blogId) throws Exception {
		if(!loggedUsers.containsKey(sessionId))
			throw new InvalidSessionException();
		loggedUsers.get(sessionId).addPostAnnouncements(blogId);
		
	}

	/**
	 * Returns the id of announcement
	 * @param sessionId
	 * @param index
	 * @return announcementId
	 * @throws Exception
	 */
	public String getAnnouncement(String sessionId, int index) throws Exception {
		if(!loggedUsers.containsKey(sessionId))
			throw new InvalidSessionException();
		
		if(index < 0 || index >= getNumberOfAnnouncements(sessionId))
			throw new InvalidIndexException();
		
		return loggedUsers.get(sessionId).getAnnouncement(index);
	}

	/**
	 * Returns a post just created with announcementId passed as parameter
	 * @param announcementId
	 * @return
	 */
	public String getPostJustCreated(String announcementId) {
		User user;
		String blogId = null;
		for (Iterator<User> it = allUsers.iterator(); it.hasNext();) {
			user = it.next();
			if(user.hasAnnouncement(announcementId)){
				blogId = user.getAnnouncementBlogId(announcementId);
			}
		}
		
		for (Iterator<User> it = allUsers.iterator(); it.hasNext();) {
			user = it.next();
			if(user.hasBlog(blogId)){
				try{
					return user.getPostAtIndex(blogId, 0);
				}catch (Exception e) {
					return null;
				}
			}
		}
	
		return null;
	}

	/**
	 * Delete a announcement
	 * @param sessionId
	 * @param announcementId
	 * @throws Exception
	 */
	public void deleteAnnouncement(String sessionId, String announcementId) throws Exception {
		if(!loggedUsers.containsKey(sessionId))
			throw new InvalidSessionException();
		loggedUsers.get(sessionId).deleteAnnouncement(announcementId);
	}
	
	//US14

	/**
	 * Create a sub blog
	 * @param sessionId
	 * @param blogId
	 * @param title
	 * @param description
	 * @return subblogId
	 * @throws Exception
	 */
	public String createSubBlog(String sessionId, String blogId, String title,
			String description) throws Exception{
		
		if (!(loggedUsers.containsKey(sessionId)))
			throw new InvalidSessionException();
		
		String id;
		for(Iterator<String> it = loggedUsers.keySet().iterator(); it.hasNext();){
			id = it.next();
			
			if(loggedUsers.get(id).hasBlog(blogId)){
				if(!id.equals(sessionId))
					throw new InvalidSessionException();
				return loggedUsers.get(id).createSubBlog(blogId, title, description);
				
			}
		}
		throw new InvalidBlogException();
	}
	

	/**
	 * Returns the number of sub blogs
	 * @param blogId
	 * @return number of sub blogs
	 * @throws Exception
	 */
	public int getNumberOfSubBlogs(String blogId) throws Exception{
		for(Iterator<User> it = allUsers.iterator(); it.hasNext();){
			User user = it.next();
			if(user.hasBlog(blogId))
				return user.getNumberOfSubBlogs(blogId);
		}
		throw new InvalidBlogException();
	}

	/**
	 * Returns the number of all sub blogs
	 * @param blogId
	 * @return number of all sub blogs
	 * @throws Exception
	 */
	public int getNumberOfAllSubBlogs(String blogId) throws Exception{
		for(Iterator<User> it = allUsers.iterator(); it.hasNext();){
			User user = it.next();
			if(user.hasBlog(blogId))
				return user.getNumberOfAllSubBlogs(blogId);
		}
		throw new InvalidBlogException();
	}

	/**
	 * Returns the id of sub blog of blog passed as parameter
	 * @param blogId
	 * @param index
	 * @return subBlogId
	 * @throws Exception
	 */
	public String getSubBlog(String blogId, int index) throws Exception{
		for(Iterator<User> it = allUsers.iterator(); it.hasNext();){
			User user = it.next();
			if(user.hasBlog(blogId))
				return user.getSubBlog(blogId, index);
		}		
		throw new InvalidBlogException();
	}

	/**
	 * Returns the number of all posts of blog passed as parameter
	 * @param blogId
	 * @return number of all posts
	 * @throws Exception
	 */
	public int getNumberOfAllPosts(String blogId) throws Exception {
		for(Iterator<User> it = allUsers.iterator(); it.hasNext();){
			User user = it.next();
			if(user.hasBlog(blogId))
				return user.getNumberOfAllPosts(blogId);
		}
		throw new InvalidBlogException();
	}

	public String addSubComment(String sessionId, String commentId, String texto) {
		// TODO Auto-generated method stub
		return null;
	}

	public String getSubComment(String commentId, int index) {
		// TODO Auto-generated method stub
		return null;
	}

	public int getNumberOfSubComments(String commentId) {
		// TODO Auto-generated method stub
		return 0;
	}

	public int getNumberOfAllSubComments(String commentId) {
		// TODO Auto-generated method stub
		return 0;
	}

	/**
	 * This method will DELETE the entire DB and remove all remaining data in memory
	 * Use it at your own risk.
	 */
	public void cleanPersistence(){
		db.cleanPersistence();
		loggedUsers.clear();
		allUsers = new ArrayList<User>();
	}
	
}
